﻿using System;
using System.Collections.Generic;
using Dataweb.NShape.Advanced;
using Dataweb.NShape;
using System.Drawing;
using cz.zcu.PreSti.Components;
using System.ComponentModel;

namespace cz.zcu.PreSti.Shapes
{
    class RepeaterSymbol : RectangleBase, ISymbol
    {
        protected override void InitializeToDefault(IStyleSet styleSet)
        {
            base.InitializeToDefault(styleSet);
            Height = 40;
            Width = 40;
        }

        public override Shape Clone()
        {
            Shape result = new RepeaterSymbol(Type, (Template)null);
            result.CopyFrom(this);
            return result;
        }

        public override void CopyFrom(Shape source)
        {
            base.CopyFrom(source);
        }

        protected override int ControlPointCount
        {
            get { return ActionsCount + EventsCount + SettersCount + GettersCount; }
        }

        public override bool HasControlPointCapability(ControlPointId controlPointId, ControlPointCapabilities controlPointCapability)
        {
            if (controlPointId > 0 && controlPointId < ActionsCount + EventsCount + SettersCount + GettersCount + 1)
                return ((controlPointCapability & ControlPointCapabilities.Connect) != 0);
            else return base.HasControlPointCapability(controlPointId, controlPointCapability);
        }


        protected internal RepeaterSymbol(ShapeType shapeType, Template template)
            : base(shapeType, template)
        {
        }


        protected override void CalcControlPoints()
        {

            int left = (int)Math.Round(-Width / 2f);
            int top = (int)Math.Round(-Height / 2f);
            int right = left + Width;
            int bottom = top + Height;

            ControlPoints[0].X = left;
            ControlPoints[0].Y = top + Height / 2;
            ControlPoints[1].X = right;
            ControlPoints[1].Y = top + Height / 2;

            for (int i = 0; i < SettersCount; i++)
            {
                int w = Width / SettersCount;
                ControlPoints[i + ActionsCount + EventsCount].X = left + i * w + w / 2;
                ControlPoints[i + ActionsCount + EventsCount].Y = top;
            }

            for (int i = 0; i < GettersCount; i++)
            {
                int w = Width / GettersCount;
                ControlPoints[i + ActionsCount + EventsCount + SettersCount].X = left + i * w + w / 2;
                ControlPoints[i + ActionsCount + EventsCount + SettersCount].Y = bottom;
            }
        }


        protected override void CalcCaptionBounds(int index, out Rectangle captionBounds)
        {
            if (index != 0) throw new IndexOutOfRangeException();
            int left = (int)Math.Round(-Width / 2f);
            int top = (int)Math.Round(-Height / 2f);
            captionBounds = Rectangle.Empty;
            captionBounds.X = left;
            captionBounds.Y = top;
            captionBounds.Width = Width;
            captionBounds.Height = Height;
        }


        protected override bool CalculatePath()
        {
            if (base.CalculatePath())
            {
                int left = (int)Math.Round(-Width / 2f);
                int top = (int)Math.Round(-Height / 2f);
                int right = left + Width;
                int bottom = top + Height;

                shapeRect.X = left;
                shapeRect.Y = top;
                shapeRect.Width = Width;
                shapeRect.Height = Height;

                Path.Reset();
                Path.StartFigure();
                Path.AddRectangle(shapeRect);
                PointF[] a = { new PointF(left, top + Height / 2f - connectorWidth), new PointF((float)left + connectorWidth, top + Height / 2f), new PointF(left, top + Height / 2f + connectorWidth) };
                Path.AddPolygon(a);
                PointF[] b = { new PointF(right, top + Height / 2f - connectorWidth), new PointF((float)right - connectorWidth, top + Height / 2f), new PointF(right, top + Height / 2f + connectorWidth) };
                Path.AddPolygon(b);
                Path.CloseFigure();
                Path.AddEllipse(-5, -5, 10, 10);
                Path.CloseFigure();
                for (int i = 0; i < SettersCount; i++)
                {
                    int w = Width / SettersCount;
                    int posX = left + i * w + w / 2;
                    Path.AddCurve(new PointF[] { new PointF(posX - 4, top), new PointF(posX, top + 4), new PointF(posX + 4, top) }, 1);
                }

                Path.StartFigure();
                for (int i = 0; i < GettersCount; i++)
                {
                    int w = Width / GettersCount;
                    int posX = left + i * w + w / 2;
                    Path.AddCurve(new PointF[] { new PointF(posX - 4, bottom), new PointF(posX, bottom - 4), new PointF(posX + 4, bottom) }, 1);
                }
                return true;
            }
            return false;
        }


        #region Fields
        private int connectorWidth = 5;
        private Rectangle shapeRect;
        #endregion

        #region ISymbol Members

        public BaseComponent initializeComponent(IPresentation p)
        {
            RepeaterModel model = (RepeaterModel)this.ModelObject;
            Repeater repeater = new Repeater(p);
            repeater.Delay = model.RepetitionPeriod;
            repeater.RepetitionRate = model.RepetitionRate;
            return repeater;
        }

        public virtual int ActionsCount
        {
            get { return 1; }
        }

        public virtual int EventsCount
        {
            get { return 1; }
        }

        public virtual int SettersCount
        {
            get { return 2; }
        }

        public virtual int GettersCount
        {
            get { return 1; }
        }

        public virtual string GetTitleForAction(int id)
        {
            return "Start";
        }

        public virtual string GetTitleForEvent(int id)
        {
            return "Repeater invocation";
        }

        public string GetTitleForSetter(int id)
        {
            switch (id)
            {
                case 0: return "Repetition period";
                case 1: return "Repetition rate";
                default: return "";
            }
        }

        public string GetTitleForGetter(int id)
        {
            switch (id)
            {
                case 0: return "Round number";
                default: return "";
            }
        }

        #endregion

        internal static Shape CreateInstance(ShapeType shapeType, Template template)
        {
            return new RepeaterSymbol(shapeType, template);
        }

    }

    public class RepeaterModel : ModelObjectBase
    {
        #region Fields

        private int repetitionRate = 5;
        private int repetitionPeriod = 5000;
        private char securityDomainName = 'A';

        private const int PropertyIdRepetitionRate = 1;
        private const int PropertyIdRepetitionPeriod = 2;

        #endregion

        #region Properties

        [Category("Presentation")]
        [Description("Repetition rate")]
        [PropertyMappingId(PropertyIdRepetitionRate)]
        public int RepetitionRate
        {
            get
            {
                return repetitionRate;
            }
            set
            {
                repetitionRate = value;
            }
        }

        [Category("Presentation")]
        [Description("Repetition period in miliseconds")]
        [PropertyMappingId(PropertyIdRepetitionPeriod)]
        public int RepetitionPeriod
        {
            get
            {
                return repetitionPeriod;
            }
            set
            {
                repetitionPeriod = value;
            }
        }

        #endregion

        public static RepeaterModel CreateInstance(ModelObjectType modelObjectType) {
			return new RepeaterModel(modelObjectType);
		}


		protected internal RepeaterModel(ModelObjectType modelObjectType)
			: base(modelObjectType)
        {
            this.terminalCount = 5;
		}


        protected internal RepeaterModel(RepeaterModel source)
			: base(source) {
            RepetitionRate = source.RepetitionRate;
            RepetitionPeriod = source.RepetitionPeriod;
            this.terminalCount = 5;
		}


		public override IModelObject Clone() {
            return new RepeaterModel(this);
		}


		public override IEnumerable<MenuItemDef> GetMenuItemDefs() {
			throw new NotImplementedException();
		}


		public override void Connect(TerminalId ownTerminalId, IModelObject targetConnector, TerminalId targetTerminalId) {
		}


		public override void Disconnect(TerminalId ownTerminalId, IModelObject targetConnector, TerminalId targetTerminalId) {
		}

        public override char SecurityDomainName
        {
            get { return securityDomainName; }
            set
            {
                if (value < 'A' || value > 'Z')
                    throw new ArgumentOutOfRangeException("SecurityDomainName", "The domain qualifier has to be an upper case  ANSI letter (A-Z).");
                securityDomainName = value;
            }
        }

        #region IEntity Members

        public static new IEnumerable<EntityPropertyDefinition> GetPropertyDefinitions(int version)
        {
            foreach (EntityPropertyDefinition pi in ModelObjectBase.GetPropertyDefinitions(version))
                yield return pi;
            yield return new EntityFieldDefinition("RepetitionRate", typeof(int));
            yield return new EntityFieldDefinition("RepetitionPeriod", typeof(int));
        }

        protected override void LoadFieldsCore(IRepositoryReader reader, int version)
        {
            base.LoadFieldsCore(reader, version);
            RepetitionRate = reader.ReadInt32();
            RepetitionPeriod = reader.ReadInt32();
        }

        protected override void SaveFieldsCore(IRepositoryWriter writer, int version)
        {
            base.SaveFieldsCore(writer, version);
            writer.WriteInt32(RepetitionRate);
            writer.WriteInt32(RepetitionPeriod);
        }

        #endregion

    }
}
